﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////

// Reviewed
#pragma once
#include "GcmpModelInterface.h"
#include "IDbObject.h"
#include "RegenDataId.h"

namespace gcmp
{
    class IDocument;
    class IElement;
    class IPositionGeometry;
    class IPositionGeometry;
    class IPositionAssociatedPlane;
    class Coordinate3d;
    class Matrix4d;
    class Vector3d;
    class IParameter;
    class IInstanceFamilyParametersUpdater;
    class ICurve2d;
    /// \brief 元素定位接口类
    ///
    /// 提供静态定位创建函数和通用接口函数
    

    FINAL_INTERFACE class GCMP_MODEL_INTERFACE_EXPORT IElementPosition : public IDbObject
    {
        DEFINE_CAST_DERIVED(gcmp::IElementPosition, gcmp::IDbObject)
    public:
        /// \brief 创建定位对象
        /// \param pElement 元素指针
        /// \param ownerId 宿主对象ElementId 
        /// \param opPositionGeometry  几何定位指针
        /// \param opPositionAssociatedPlane 关联平面指针
        /// \return 定位对象指针
        static OwnerPtr<IElementPosition> Create(IElement *pElement, OwnerPtr<IPositionGeometry> opPositionGeometry, OwnerPtr<IPositionAssociatedPlane> opPositionAssociatedPlane, std::wstring* errorMessage = nullptr);

        /// \brief 创建基于曲线在单个关联平面的定位（例如：模型线）
        /// \param pElement 元素指针
        /// \param associatedPlaneId 关联平面id
        /// \param opCurve2d  定位曲线
        /// \param isAllowRemoveAssociatedPlane 是否允许删除关联平面，true表示允许删除关联平面，false表示不允许删除关联平面
        /// \return 返回true表示宿主对象成功创建定位，否则表示创建失败。
        static bool CreateCurve2dOnSingleAssociatedPlanePositionBehavior(IElement *pElement, const ElementId &associatedPlaneId, OwnerPtr<ICurve2d> opCurve2d, bool isAllowRemoveAssociatedPlane = false);
       
        /// \brief 创建基于曲线在单个关联平面的定位（例如：模型线）
        /// \param pElement 元素指针
        /// \param associatedPlaneId 关联平面id
        /// \param points  定位点集
        /// \param isAllowRemoveAssociatedPlane 是否允许删除关联平面，true表示允许删除关联平面，false表示不允许删除关联平面
        /// \return 返回true表示宿主对象成功创建定位，否则表示创建失败。
        static bool CreateCurve2dOnSingleAssociatedPlanePositionBehavior(IElement *pElement, const ElementId &associatedPlaneId, const std::vector<Vector3d>& points, bool isAllowRemoveAssociatedPlane = false);
       
        /// \brief 创建基于曲线在顶部关联平面的定位（例如：条形基础）
        /// \param pElement 元素指针
        /// \param associatedPlaneId 关联平面id
        /// \param points  定位点集 points
        /// \return 返回true表示宿主对象成功创建定位，否则表示创建失败。
        static bool CreateCurve2dOnTopAssociatedPlanePositionBehavior(IElement *pElement, const ElementId &associatedPlaneId, const std::vector<Vector3d> &points);

        /// \brief 创建基于曲线在顶部关联平面带两个偏移的定位（例如：梁）
        /// \param pElement 元素指针
        /// \param associatedPlaneId 关联平面id
        /// \param points  定位点集
        /// \return 返回true表示宿主对象成功创建定位，否则表示创建失败。
        static bool CreateCurve2dOnTopAssociatedPlaneWithTwoOffsetsPositionBehavior(IElement *pElement, const ElementId &associatedPlaneId, const std::vector<Vector3d> &points);

        /// \brief 创建基于曲线在底部关联平面的定位（例如：反檐）
        /// \param pElement 元素指针
        /// \param associatedPlaneId 关联平面id
        /// \param points  定位点集 points
        /// \return 返回true表示宿主对象成功创建定位，否则表示创建失败。
        static bool CreateCurve2dOnBottomAssociatedPlanePositionBehavior(IElement *pElement, const ElementId &associatedPlaneId, const std::vector<Vector3d> &points);

        /// \brief 创建基于曲线在底部关联平面带两个偏移的定位（例如：GBMP的旧梁）
        /// \param pElement 元素指针
        /// \param associatedPlaneId 关联平面id
        /// \param points  定位点集
        /// \return 返回true表示宿主对象成功创建定位，否则表示创建失败。
        static bool CreateCurve2dOnBottomAssociatedPlaneWithTwoOffsetsPositionBehavior(IElement *pElement, const ElementId &associatedPlaneId, const std::vector<Vector3d> &points);
        
        /// \brief 创建基于曲线在两个关联平面的定位（例如：普通墙定位）
        /// \param pElement 元素指针
        /// \param bottomAssociatedPlaneId 底部关联平面id
        /// \param bottomPlaneOffset 底部关联平面偏移
        /// \param points  定位点集
        /// \param topAssociatedPlaneId 顶部关联平面id，可以允许设置无效值
        /// \param topPlaneOffset 顶部关联平面偏移
        /// \return 返回true表示宿主对象成功创建定位，否则表示创建失败。
        static bool CreateCurve2dOnTwoAssociatedPlanesPositionBehavior(IElement *pElement, const ElementId &bottomAssociatedPlaneId, double bottomPlaneOffset, const std::vector<Vector3d> &points, const ElementId &topAssociatedPlaneId, double topPlaneOffset);
       
        /// \brief 创建基于曲线在两个关联平面带四个偏移设置的定位（例如：变截面墙定位）
        /// \param pElement 元素指针
        /// \param bottomAssociatedPlaneId 底部关联平面id
        /// \param points 定位点集
        /// \param topAssociatedPlaneId 顶部关联平面id
        /// \return 返回true表示宿主对象成功创建定位，否则表示创建失败。
        static bool CreateCurve2dOnTwoAssociatedPlanesWithFourOffsetsPositionBehavior(IElement *pElement, const ElementId &bottomAssociatedPlaneId, const std::vector<Vector3d> &points, const ElementId &topAssociatedPlaneId);
        
        /// \brief 创建基于曲线在坐标系的定位（例如：线式族定位）
        /// \param pElement 元素指针
        /// \param coordinate 坐标系
        /// \param points 定位点集
        /// \return 返回true表示宿主对象成功创建定位，否则表示创建失败。
        static bool CreateCurve2dOnAssociatedCoordinatePositionBehavior(IElement *pElement, const Coordinate3d &coordinate, const std::vector<Vector3d> &points);
    
        /// \brief 创建基于PolyCurve在坐标系的定位（例如：栏杆扶手定位）
        /// \param pElement 元素指针
        /// \param associatedPlaneId 关联平面Id
        /// \param points 定位点集
        /// \return 返回true表示宿主对象成功创建定位，否则表示创建失败。
        static bool CreatePolyCurve2dOnSingleAssociatedPlanePositionBehavior(IElement *pElement, const ElementId &associatedPlaneId, const std::vector<Vector3d> &points);
        
        /// \brief 创建基于点在线上的定位（例如：窗、门等在墙上的定位）,关联平面为底部关联平面
        /// \param pElement 元素指针
        /// \param associatedPlaneId  关联平面Id
        /// \param position 定位点
        /// \return 返回true表示宿主对象成功创建定位，否则表示创建失败。
        static bool CreatePointOnCurve2dOnBottomAssociatedPlanePositionBehavior(IElement *pElement, const ElementId &associatedPlaneId, const Vector3d &position);

        /// \brief 创建基于点在线上的定位（例如：窗、门等在墙上的定位）,关联平面为顶部关联平面
        /// \param pElement 元素指针
        /// \param associatedPlaneId  关联平面Id
        /// \param position 定位点
        /// \return 返回true表示宿主对象成功创建定位，否则表示创建失败。
        static bool CreatePointOnCurve2dOnTopAssociatedPlanePositionBehavior(IElement *pElement, const ElementId &associatedPlaneId, const Vector3d &position);

        /// \brief 创建基于点基于另一个宿主点定位方式（例如：板洞在板上）
        /// \param pElement 元素指针
        /// \param associatedPlaneId 关联平面Id
        /// \param position 定位点
        /// \param directionX 定位x方向 
        /// \param directionY 定位y方向
        /// \return 返回true表示宿主对象成功创建定位，否则表示创建失败。
        static bool CreatePointRelativeHostPoint2dOnSingleAssociatedPlanePositionBehavior(IElement *pElement, const ElementId &associatedPlaneId, const Vector3d &position, const Vector3d &directionX, const Vector3d &directionY);

        /// \brief 创建基于点在两个关联平面上的定位（例如：垂直柱）
        /// \param pElement 元素指针
        /// \param bottomAssociatedPlaneId 底部关联平面id
        /// \param position  定位点
        /// \param directionX 定位x方向 
        /// \param directionY 定位y方向
        /// \param topAssociatedPlaneId 顶部关联平面id
        /// \return 返回true表示宿主对象成功创建定位，否则表示创建失败。
        static bool CreatePoint2dOnTwoAssociatedPlanesPositionBehavior(IElement *pElement, const ElementId &bottomAssociatedPlaneId, const Vector3d &position, const Vector3d &directionX, const Vector3d &directionY, const ElementId &topAssociatedPlaneId);

        /// \brief 创建基于点在单个关联平面上的定位（例如：点式族）
        /// \param pElement 元素指针
        /// \param associatedPlaneId 关联平面
        /// \param position  定位点
        /// \param directionX 定位x方向 
        /// \param directionY 定位y方向
        /// \param offset 偏移量
        /// \return 返回true表示宿主对象成功创建定位，否则表示创建失败。
        static bool CreatePoint2dOnSingleAssociatedPlanePositionBehavior(IElement *pElement, const ElementId &associatedPlaneId, const Vector3d &position, const Vector3d &directionX, const Vector3d &directionY, double offset = 0);

        /// \brief 创建基于点在底部关联平面（关联底部标高）上的定位（例如：基础）
        ///
        ///  与CreatePoint2dOnSingleAssociatedPlanePositionBehavior区别是关联平面参数不一样，采用的是关联底部标高参数
        /// \param pElement 元素指针
        /// \param bottomAssociatedPlaneId 关联平面
        /// \param position  定位点
        /// \param directionX 定位x方向 
        /// \param directionY 定位y方向
        /// \param offset 偏移量
        /// \return 返回true表示宿主对象成功创建定位，否则表示创建失败。
        static bool CreatePoint2dOnBottomAssociatedPlanePositionBehavior(IElement *pElement, const ElementId &bottomAssociatedPlaneId, const Vector3d &position, const Vector3d &directionX, const Vector3d &directionY, double offset = 0);

        /// \brief 创建基于点在顶部关联平面（关联底部标高）上的定位（例如：板）
        ///
        ///  与CreatePoint2dOnSingleAssociatedPlanePositionBehavior区别是关联平面参数不一样，采用的是关联顶部标高参数
        /// \param pElement 元素指针
        /// \param topAssociatedPlaneId 顶部关联平面
        /// \param position  定位点
        /// \param directionX 定位x方向 
        /// \param directionY 定位y方向
        /// \param offset 偏移量
        /// \return 返回true表示宿主对象成功创建定位，否则表示创建失败。
        static bool CreatePoint2dOnTopAssociatedPlanePositionBehavior(IElement *pElement, const ElementId &topAssociatedPlaneId, const Vector3d& position, const Vector3d& directionX, const Vector3d& directionY, double offset = 0);
        
        /// \brief 创建基于点在关联坐标系上的定位（例如：点式族）
        /// \param pElement 元素指针
        /// \param coordinate 坐标系
        /// \param position  定位点
        /// \param directionX 定位x方向 
        /// \param directionY 定位y方向
        /// \param offset 偏移量
        /// \return 返回true表示宿主对象成功创建定位，否则表示创建失败。
        static bool CreatePoint2dOnAssociatedCoordinatePositionBehavior(IElement *pElement, const Coordinate3d &coordinate, const Vector3d& position, const Vector3d& directionX, const Vector3d& directionY, double offset = 0);

        /// \brief 根据对象指针得到定位中的关联平面id
        /// \param pElement 对象指针
        /// \return  关联平面Id
        static ElementId GetAssociatedPlaneId(const IElement *pElement);

    public:

        /// \brief 克隆定位对象
        /// \return 克隆后的定位对象
        virtual OwnerPtr<IElementPosition> Clone() const = 0;

        /// \brief 设置行为所属Element
        /// \param pOwnerElement 所属Element
        /// \return bool
        virtual bool SetOwnerElement(IElement* pOwnerElement) = 0;

        /// \brief 获得行为所属的Element
        /// \return 所属的Element
        virtual IElement* GetOwnerElement() = 0;

        /// \brief 获得行为所属的Element
        /// \return 所属的Element
        virtual const IElement* GetOwnerElement() const = 0;

        /// \brief 设置几何定位
        /// \param opPositionGeometry 几何定位指针
        /// \return 返回true表示成功设置，否则表示失败 
        virtual bool SetPositionGeometry(OwnerPtr<IPositionGeometry> opPositionGeometry) = 0;

        /// \brief 设置关联平面定位
        /// \param opPositionAssociatedPlane 关联平面定位指针
        /// \return 返回true表示成功设置，否则表示失败
        virtual bool SetPositionAssociatedPlane(OwnerPtr<IPositionAssociatedPlane> opPositionAssociatedPlane) = 0;

        /// \brief 得到几何定位指针
        /// \return 几何定位指针
        virtual const IPositionGeometry* GetPositionGeometry() const = 0;

        /// \brief 得到几何定位指针
        /// \return 几何定位指针
        virtual IPositionGeometry* GetPositionGeometry() = 0;

        /// \brief 得到关联平面定位指针
        /// \return 关联平面定位指针
        virtual const IPositionAssociatedPlane* GetPositionAssociatedPlane() const = 0;

        /// \brief 得到关联平面定位指针
        /// \return 关联平面定位指针
        virtual IPositionAssociatedPlane* GetPositionAssociatedPlane() = 0;

        /// \brief 得到基础关联平面id
        /// 
        /// 若只有一个关联平面时，则baseAssocitedPlane就是那个关联平面
        /// 若有顶底两个关联平面时，则baseAssocitedPlane为底部关联平面
        /// \return 基础关联平面id
        virtual ElementId GetBaseAssociatedPlaneId()const = 0;

        /// \brief 设置基础关联平面id
        ///
        /// 若只有一个关联平面时，则baseAssocitedPlane就是那个关联平面
        /// 若有顶底两个关联平面时，则baseAssocitedPlane为底部关联平面
        /// \param associatedPlaneId 关联平面id
        /// \return 返回true表示成功设置，否则表示失败
        virtual bool SetBaseAssociatedPlaneId(const ElementId &associatedPlaneId) = 0;

        /// \brief 得到基础关联平面高度值
        /// \return 基础关联平面标高度值
        virtual double GetBaseAssociatedPlaneHeight() const = 0;

        /// \brief 判断是否允许删除单个关联平面
        /// 
        /// 只有关联单个关联平面定位时，才有可能允许删除单个关联平面。
        /// \return 返回true表示允许删除单个关联平面，否则表示禁止删除单个关联平面
        virtual bool IsAllowRemoveSingleAssociatedPlane() const = 0;

        /// \brief 删除单个关联平面 
        /// 
        /// 前置条件是关联单个平面且允许删除单个关联平面
        /// 删除单个关联平面，则会自动切换同类型关联坐标系定位
        /// \return 返回true表示成功删除单个关联平面，否则表示删除失败。
        virtual bool RemoveSingleAssociatedPlane() = 0;


        /// \brief 得到世界坐标系下的点坐标系集合
        /// \return 点坐标系集合
        virtual std::vector<Coordinate3d> GetWorldCoordinateSystems() const = 0;

        /// \brief 得到局部坐标系下的点坐标系集合
        /// \return 点坐标系集合
        virtual std::vector<Coordinate3d> GetLocalCoordinateSystems() const = 0;

        /// \brief 计算定位局部坐标系到世界坐标系下的转换矩阵
        /// \return 转换矩阵
        virtual Matrix4d ComputeLocalToWorldCoordinateSystemTransformMatrix() const = 0;

        /// \brief 得到控制点个数
        /// \return 控制点个数
        virtual int GetControlPointCount() const = 0;

        /// \brief 通过控制点索引得到世界坐标系上的坐标点
        /// \param index 控制点索引
        /// \return 世界坐标系上的坐标点
        virtual Vector3d GetPointByIndex(int index) const = 0;

        /// \brief 通过控制点索引设置控制点在世界坐标系上的坐标点
        /// \param index 控制点索引
        /// \param position 世界坐标系上的坐标点
        /// \return 返回true表示成功设置，否则表示失败 
        virtual bool SetPointByIndex(int index, const Vector3d& position) = 0;

        /// \brief 执行移动操作
        /// \param moveDirection 移动方向向量
        /// \return 返回true表示成功执行移动操作，否则表示失败 
        virtual bool Translate(const Vector3d& moveDirection) = 0;

        /// \brief 执矩阵转换操作
        /// \param matrix 转换矩阵
        /// \return 返回true表示成功矩阵转换操作，否则表示失败 
        virtual bool Transform(const Matrix4d& matrix) = 0;

        /// \brief 得到基准关联平面的坐标系
        /// \return 基准关联平面的坐标系
        virtual Coordinate3d GetBasePlaneCoordinate3d() const = 0;

        /// \brief 得到基准平面偏移量
        /// \return 基准平面偏移量
        virtual double GetBasePlaneOffset() const = 0;

  
        /// \brief 报出参数定义索引集合
        /// \param pParameterDefinitionIds 参数定义索引集合
        /// \return void
        virtual void ReportParameterDefinitions(std::vector<int>* pParameterDefinitionIds) const = 0;

        /// \brief 根据参数定义索引得到原生参数
        /// \param parameterDefinitionId 参数定义索引
        /// \return 参数
        virtual OwnerPtr<IParameter> GetNativeParameter(int parameterDefinitionId) const = 0;

        /// \brief 设置原生参数
        /// \param pParameter 参数
        /// \param errorMsg 指针有效表示输出错误信息，否则不输出错误信息errorMsg
        /// \return 返回true表示成功设置，否则表示失败 
        virtual bool SetNativeParameter(const IParameter *pParameter, std::wstring* errorMsg = nullptr) = 0;

        /// \brief 判断是否为定位参数
        /// \param parameterDefinitionId
        /// \return 返回true表示是个定位参数，否则表示不是定位参数
        virtual bool IsPositionParameter(int parameterDefinitionId) const = 0;

        /// \brief 判断参数是否允许被修改
        /// \param parameterDefinitionId
        /// \return 返回true表示是参数允许修改，否则表示不允许修改
        virtual bool IsParameterModifiable(int parameterDefinitionId) const = 0;

        /// \brief 得到参数更新对象
        /// \return 参数更新对象 
        virtual const IInstanceFamilyParametersUpdater * GetParametersUpdater() const = 0;

        /// \brief设置参数更新对象
        /// \param opParametersUpdater 参数更新对象
        /// \return 返回true表示是成功设置，否则表示失败
        virtual bool SetParametersUpdater(OwnerPtr<IInstanceFamilyParametersUpdater> opParametersUpdater) = 0;

        /// \brief 把数据更新到族参数中
        /// \return 返回true表示是成功更新，否则表示失败
        virtual bool UpdatePositionParametersToFamilyParameters() = 0;       

        /// \brief 得到起始偏移关联更新变化Id
        /// \return 起始偏移关联更新变化Id
        virtual RegenDataId GetStartOffsetRdId() const = 0;

        /// \brief 得到终止偏移关联更新变化Id
        /// \return 终止偏移关联更新变化Id
        virtual RegenDataId GetEndOffsetRdId() const = 0;

        /// \brief 得到关联平面的关联更新变化Id
        /// \return 关联平面的关联更新变化Id
        virtual RegenDataId GetAssociatedPlaneIdRdId() const = 0;

        /// \brief 得到顶部关联平面的关联更新变化Id
        /// \return 顶部关联平面的关联更新变化Id
        virtual RegenDataId GetTopAssociatedPlaneIdRdId() const = 0;

        /// \brief 标志起始偏移关联更新变化Id
        /// \return void
        virtual void MarkStartOffsetRdId() = 0;

        /// \brief 标志终止偏移关联更新变化Id
        /// \return void
        virtual void MarkEndOffsetRdId() = 0;

        /// \brief 标志关联平面的关联更新变化Id
        /// \return void
        virtual void MarkAssociatedPlaneIdRdId() = 0;

        /// \brief 标志顶部关联平面的关联更新变化Id
        /// \return void
        virtual void MarkTopAssociatedPlaneIdRdId() = 0;
    };
}



